/* -*- sh -*- */

/*
 * Linker script for i386 images
 *
 */

OUTPUT_FORMAT ( "elf32-i386", "elf32-i386", "elf32-i386" )
OUTPUT_ARCH ( i386 )

SECTIONS {

    /* All sections in the resulting file have consecutive load
     * addresses, but may have individual link addresses depending on
     * the memory model being used.
     *
     * The linker symbols _prefix_link_addr, load_addr, and
     * _max_align may be specified explicitly.  If not specified, they
     * will default to:
     *
     *   _prefix_link_addr	= 0
     *   _load_addr		= 0
     *   _max_align		= 16
     * 
     * We guarantee alignment of virtual addresses to any alignment
     * specified by the constituent object files (e.g. via
     * __attribute__((aligned(x)))).  Load addresses are guaranteed
     * only up to _max_align.  Provided that all loader and relocation
     * code honours _max_align, this means that physical addresses are
     * also guaranteed up to _max_align.
     *
     * Note that when using -DKEEP_IT_REAL, the UNDI segments are only
     * guaranteed to be loaded on a paragraph boundary (i.e. 16-byte
     * alignment).  Using _max_align>16 will therefore not guarantee
     * >16-byte alignment of physical addresses when -DKEEP_IT_REAL is
     * used (though virtual addresses will still be fully aligned).
     *
     */

    /*
     * The prefix
     */

    _prefix_link_addr = DEFINED ( _prefix_link_addr ) ? _prefix_link_addr : 0;
    . = _prefix_link_addr;
    _prefix = .;

    .prefix : AT ( _prefix_load_offset + __prefix ) {
	__prefix = .;
	_entry = .;
	*(.prefix)
	*(.prefix.*)
	_eprefix_progbits = .;
    }
    
    _eprefix = .;

    /*
     * The 16-bit sections
     */

    _text16_link_addr = 0;
    . = _text16_link_addr;
    _text16 = .;

    . += 1;			/* Prevent NULL being valid */

    .text16 : AT ( _text16_load_offset + __text16 ) {
	__text16 = .;
	KEEP(*(.text.null_trap))
	KEEP(*(.text.null_trap.*))
	*(.text16)
	*(.text16.*)
	*(.text)
	*(.text.*)
	_etext16_progbits = .;
    } = 0x9090

    _etext16 = .;

    _data16_link_addr = 0;
    . = _data16_link_addr;
    _data16 = .;

    . += 1;			/* Prevent NULL being valid */

    .rodata16 : AT ( _data16_load_offset + __rodata16 ) {
	__rodata16 = .;
	*(.rodata16)
	*(.rodata16.*)
	*(.rodata)
	*(.rodata.*)
    }
    .data16 : AT ( _data16_load_offset + __data16 ) {
	__data16 = .;
	*(.data16)
	*(.data16.*)
	*(.data)
	*(.data.*)
	KEEP(*(SORT(.tbl.*)))	/* Various tables.  See include/tables.h */
	KEEP(*(.provided))
	KEEP(*(.provided.*))
	_edata16_progbits = .;
    }
    .bss16 : AT ( _data16_load_offset + __bss16 ) {
	__bss16 = .;
	_bss16 = .;
	*(.bss16)
	*(.bss16.*)
	*(.bss)
	*(.bss.*)
	*(COMMON)
	_ebss16 = .;
    }
    .stack16 : AT ( _data16_load_offset + __stack16 ) {
	__stack16 = .;
	*(.stack16)
	*(.stack16.*)
	*(.stack)
	*(.stack.*)
    }

    _edata16 = .;

    _end = .;

    /*
     * Dispose of the comment and note sections to make the link map
     * easier to read
     */

    /DISCARD/ : {
	*(.comment)
	*(.comment.*)
	*(.note)
	*(.note.*)
	*(.discard)
	*(.discard.*)
	*(.sbat)
	*(.sbat.*)
    }

    /*
     * Load address calculations.  The slightly obscure nature of the
     * calculations is because ALIGN(x) can only operate on the
     * location counter.
     */

    _max_align		    = DEFINED ( _max_align ) ? _max_align : 16;
    _load_addr		    = DEFINED ( _load_addr ) ? _load_addr : 0;

    .			    = _load_addr;

    .			   -= _prefix_link_addr;
    _prefix_load_offset	    = ALIGN ( _max_align );
    _prefix_load_addr	    = _prefix_link_addr + _prefix_load_offset;
    _prefix_size	    = _eprefix - _prefix;
    _prefix_progbits_size   = _eprefix_progbits - _prefix;
    .			    = _prefix_load_addr + _prefix_progbits_size;

    .			   -= _text16_link_addr;
    _text16_load_offset	    = ALIGN ( _max_align );
    _text16_load_addr	    = _text16_link_addr + _text16_load_offset;
    _text16_size	    = _etext16 - _text16;
    _text16_progbits_size   = _etext16_progbits - _text16;
    .			    = _text16_load_addr + _text16_progbits_size;

    .			   -= _data16_link_addr;
    _data16_load_offset	    = ALIGN ( _max_align );
    _data16_load_addr	    = _data16_link_addr + _data16_load_offset;
    _data16_size	    = _edata16 - _data16;
    _data16_progbits_size   = _edata16_progbits - _data16;
    .			    = _data16_load_addr + _data16_progbits_size;

    .			    = ALIGN ( _max_align );

    _load_size		    = . - _load_addr;

    /*
     * Alignment checks.  ALIGN() can only operate on the location
     * counter, so we set the location counter to each value we want
     * to check.
     */

    . = _prefix_load_addr - _prefix_link_addr;
    _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
		       "_prefix is badly aligned" );

    . = _text16_load_addr - _text16_link_addr;
    _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
		       "_text16 is badly aligned" );

    . = _data16_load_addr - _data16_link_addr;
    _assert = ASSERT ( ( . == ALIGN ( _max_align ) ),
		       "_data16 is badly aligned" );

    /*
     * Values calculated to save code from doing it
     */
    _text16_size_pgh	= ( ( _text16_size + 15 ) / 16 );
    _data16_size_pgh	= ( ( _data16_size + 15 ) / 16 );
    _load_size_pgh	= ( ( _load_size + 15 ) / 16 );
    _load_size_sect	= ( ( _load_size + 511 ) / 512 );
}
